﻿// Shader-Based-Image-Processing (SBIP)
// http://code.google.com/p/sbip/
//
// Copyright © Frank Nagl, 2009-2011
// admin@franknagl.de
//
namespace SBIP.Helper
{
    using System.Drawing;
    using System.IO;
    using Microsoft.Xna.Framework.Graphics;
    using System.Drawing.Imaging;

    /// <summary>
    /// Helper class for loading, saving and cloning XNA textures. 
    /// See function details for more information.
    /// </summary>
    public static class TextureIOAndCloner
    {
        /// <summary>Deep-clones a Texture2D object.</summary>
        /// <param name="source">The source texture.</param>
        /// <returns>The cloned texture.</returns>
        public static Texture2D CloneTexture(Texture2D source)
        {
            byte[] texData = new byte[4 * source.Width * source.Height];
            source.GetData(texData);

            Texture2D destination = new Texture2D(
                source.GraphicsDevice, 
                source.Width, 
                source.Height, 
                source.LevelCount != 1, 
                source.Format);

            destination.SetData(texData);
            return destination;
        }

        /// <summary>
        /// Loads a texture from file.
        /// </summary>
        /// <param name="filename">The filename (including its path).</param>
        /// <param name="graphicsDevice">The XNA graphics device.</param>
        /// <returns>The loaded texture.</returns>
        public static Texture2D LoadTextureFromFile(
            string filename, 
            GraphicsDevice graphicsDevice)
        {
            Texture2D texture;
            using (Stream stream = File.OpenRead(filename))
            {
                texture = Texture2D.FromStream(graphicsDevice, stream);
            }
            
            return texture;
        }

        /// <summary>
        /// Loads a texture from file.
        /// </summary>
        /// <param name="filename">The filename (including its path).</param>
        /// <param name="graphicsDevice">The XNA graphics device.</param>
        /// <param name="width">The requested texture width.</param>
        /// <param name="height">The requested texture height.</param>
        /// <param name="zoom">Control the aspect ratio when zooming (scaling); 
        /// set to false to maintain a constant aspect ratio, true otherwise. 
        /// See remarks.</param>
        /// <remarks>
        /// <para>
        /// When zooming, the image is scaled relative to the image center.
        /// Set <b>zoom</b> to false to maintain the aspect ratio which may 
        /// result in the <b>width</b> or <b>height</b> returned not matching 
        /// the values requested.
        /// Set <b>zoom</b> to true to scale the image to fit the requested 
        /// <b>width</b> and <b>height</b> regardless of the aspect ratio. 
        /// This may result in clipping some of the original image.
        /// </para>
        /// </remarks>
        /// <returns>The loaded texture.</returns>
        public static Texture2D LoadTextureFromFile(
            string filename,
            GraphicsDevice graphicsDevice,
            int width,
            int height,
            bool zoom)
        {
            Texture2D texture;
            using (Stream stream = File.OpenRead(filename))
            {
                texture = Texture2D.FromStream(
                    graphicsDevice, stream, width, height, zoom);
            }

            return texture;
        }

        /// <summary>Saves a XNA texture as JPEG image.</summary>
        /// <param name="texture">The texture to save.</param>
        /// <param name="jpgFilename">Filename of the destination image.</param>
        /// <param name="width">The new width to use for saving.</param>
        /// <param name="height">The new height to use for saving.</param>
        public static void SaveTextureAs32BitJpeg(
            Texture2D texture, string jpgFilename, int width = -1, int height = -1)
        {
            int w = width == -1 ? texture.Width : width;
            int h = height == -1 ? texture.Height : height;

            using (Stream stream = File.OpenWrite(jpgFilename))
            {
                texture.SaveAsJpeg(stream, w, h);
            }
        }

        /// <summary> Saves a XNA texture as PNG image. </summary>
        /// <param name="texture">The texture to save.</param>
        /// <param name="pngFilename">Filename of the destination image.</param>
        /// <param name="newWidth">The new width to use for saving.</param>
        /// <param name="newHeight">The new height to use for saving.</param>
        public static void SaveTextureAs8BitPng(
            Texture2D texture, 
            string pngFilename, 
            int newWidth = -1, 
            int newHeight = -1)
        {
            int w = newWidth == -1 ? texture.Width : newWidth;
            int h = newHeight == -1 ? texture.Height : newHeight;

            Bitmap bitmap = BitmapToTexture.TextureTo8Bit(texture);
            if (w != texture.Width)
            {
                bitmap = BitmapHelper.CloneBitmap(
                    bitmap, w, h, PixelFormat.Format8bppIndexed);
                ColorPalette.SetColorPaletteToGray(bitmap);
            }
            bitmap.Save(pngFilename);
        }

        /// <summary> Saves a XNA texture as 24 bit PNG image. </summary>
        /// <param name="texture">The texture to save.</param>
        /// <param name="pngFilename">Filename of the destination image.</param>
        /// <param name="width">The new width to use for saving.</param>
        /// <param name="height">The new height to use for saving.</param>
        public static void SaveTextureAs24BitPng(
            Texture2D texture, string pngFilename, int width = -1, int height = -1)
        {
            int w = width == -1 ? texture.Width : width;
            int h = height == -1 ? texture.Height : height;

            Bitmap bitmap = BitmapToTexture.TextureTo24Bit(texture);
            if (w != texture.Width)
            {
                bitmap = BitmapHelper.CloneBitmap(
                    bitmap, w, h, PixelFormat.Format24bppRgb);
            }
            ////---
            //ImageCodecInfo imageCodecInfoPNG = GetEncoderInfo("image/png");
            //EncoderParameters ep = new EncoderParameters(2);
            //ep.Param[0] = new EncoderParameter(
            //    Encoder.Compression, (long)EncoderValue.RenderProgressive);
            //ep.Param[1] = new EncoderParameter(Encoder.ColorDepth, 24L);
            //bitmap.Save(pngFilename, imageCodecInfoPNG, ep);
            ////---
            bitmap.Save(pngFilename);
        }  

        /// <summary> Saves a XNA texture as 32 bit PNG image. It seems to have 
        /// better compression than 24 bit version of this method.</summary>
        /// <param name="texture">The texture to save.</param>
        /// <param name="pngFilename">Filename of the destination image.</param>
        /// <param name="width">The new width to use for saving.</param>
        /// <param name="height">The new height to use for saving.</param>
        public static void SaveTextureAs32BitPng(
            Texture2D texture, string pngFilename, int width = -1, int height = -1)
        {
            int w = width == -1 ? texture.Width : width;
            int h = height == -1 ? texture.Height : height;

            using (Stream stream = File.OpenWrite(pngFilename))
            {
                texture.SaveAsPng(stream, w, h);
            }            
        }

        ///// <summary>
        ///// Returns the image codec with the given mime type
        ///// </summary>
        //private static ImageCodecInfo GetEncoderInfo(string mimeType)
        //{
        //    // Get image codecs for all image formats
        //    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

        //    // Find the correct image codec
        //    for (int i = 0; i < codecs.Length; i++)
        //        if (codecs[i].MimeType == mimeType)
        //            return codecs[i];
        //    return null;
        //} 
    }
}
